#include <iostream>
#include <memory>
#include <string>

//水果类
class Fruit
{
public:
    virtual void name() = 0; //纯虚函数
};

class Apple : public Fruit
{
public:
    //重写
    void name() override
    {
        std::cout << "这是苹果\n";
    }
};

class Banana : public Fruit
{
public:
    //重写
    void name() override
    {
        std::cout << "这是香蕉\n";
    }
};

//动物类
class Animal
{
public:
    virtual void name() = 0;//纯虚函数
};

class Lamp : public Animal
{
public:
    void name() override
    {
        std::cout << "这是一只山羊\n";
    }
};

class Dog : public Animal
{
public:
    void name() override
    {
        std::cout << "这是一只小狗\n";
    }
};

//简单工厂模式:
//1.优点：实现简单、通俗易懂 
//2.缺点：产品太多会导致代码庞大，并且违背开闭原则
// class FruitFactory
// {
// public:
//     static std::shared_ptr<Fruit> create(const std::string& name)
//     {
//         if(name == "苹果")
//         {
//             return std::make_shared<Apple>(); //生产苹果
//         }
//         else if(name == "香蕉")
//         {
//             return std::make_shared<Banana>(); //生产香蕉
//         }
//     }
// };

//工厂方法模式：一个产品一个工厂，一个工厂只生产一个产品
//1.缺点：当产品很多、工厂类很大，编写大量的代码，造成臃肿
// class FruitFactory
// {
// public:
//     virtual std::shared_ptr<Fruit> create() = 0;
// };
// //苹果工厂
// class AppleFactory : public FruitFactory
// {
// public:
//     std::shared_ptr<Fruit> create() override
//     {
//         std::cout << "苹果生产成功\n";
//         return std::make_shared<Apple>(); //生产苹果
//     }
// };
// //香蕉工厂
// class BananaFactory : public FruitFactory
// {
// public:
//     std::shared_ptr<Fruit> create() override
//     {
//         std::cout << "香蕉生产成功\n";
//         return std::make_shared<Banana>();//生产香蕉
//     }
// };

//抽象工厂模式：由两部分组成
//1.抽象工厂
//2.具体子类工厂

//抽象工厂
class Factory
{
public:
    //用于生产水果
    virtual std::shared_ptr<Fruit> getFruit(const std::string& name) = 0;
    //用于生产动物
    virtual std::shared_ptr<Animal> getAnimal(const std::string& name) = 0;
};

//具体的子类工厂
//水果类工厂
class FruitFactory : public Factory //继承抽象类工厂
{
public:
    //重写:生产动物
    std::shared_ptr<Animal> getAnimal(const std::string& name) override
    {
        //水果工厂不生产动物，直接返回空指针
        return std::shared_ptr<Animal>();
    }
    //重写:生产水果
    std::shared_ptr<Fruit> getFruit(const std::string& name) override
    {
        if(name == "苹果")
        {
            return std::make_shared<Apple>(); //生产苹果对象
        }
        else if(name == "香蕉")
        {
            return std::make_shared<Banana>();//生产香蕉对象
        }
    }
};
//动物工厂
class AnimalFactory : public Factory
{
public:
    //重写:生产水果
    std::shared_ptr<Fruit> getFruit(const std::string& name) override
    {
        //动物工厂不生产水果，直接返回空指针
        return std::shared_ptr<Fruit>();
    }
    //重写:生产动物
    std::shared_ptr<Animal> getAnimal(const std::string& name) override
    {
        if(name == "小狗")
        {
            return std::make_shared<Dog>();//生产小狗对象
        }
        else if(name == "山羊")
        {
            return std::make_shared<Lamp>();//生产山羊对象
        }
    }
};

//工厂生产者类:生产工厂
class FactoryProduer
{
public:
    static std::shared_ptr<Factory> create(const std::string& name)
    {
        if(name == "动物")
        {
            return std::make_shared<AnimalFactory>();
        }
        else if(name == "水果")
        {
            return std::make_shared<FruitFactory>();
        }
    }
};

int main()
{
    //简单工厂模式
    // std::shared_ptr<Fruit> ff1 = FruitFactory::create("苹果");
    // ff1->name();
    // std::shared_ptr<Fruit> ff2 = FruitFactory::create("香蕉");
    // ff2->name();

    //工厂方法模式
    // std::shared_ptr<FruitFactory> af(new AppleFactory());//创建苹果工厂
    // //生产苹果
    // std::shared_ptr<Fruit> ff1 = af->create();
    // //auto ff1 = af->create(); 
    // //af->create()->name();
    // ff1->name(); //苹果

    // std::shared_ptr<FruitFactory> bf(new BananaFactory());
    // std::shared_ptr<Fruit> ff2 = bf->create();
    // ff2->name();

    //抽象工厂模式
    //生成水果工厂
    std::shared_ptr<Factory> ff = FactoryProduer::create("水果");
    std::shared_ptr<Fruit> apple = ff->getFruit("苹果");
    apple->name();
    std::shared_ptr<Fruit> banana = ff->getFruit("香蕉");
    banana->name();

    //生成动物工厂
    std::shared_ptr<Factory> af = FactoryProduer::create("动物");
    std::shared_ptr<Animal> dog = af->getAnimal("小狗");
    dog->name();
    std::shared_ptr<Animal> lamp = af->getAnimal("山羊");
    lamp->name();

    return 0;
}